package org.hackystat.devcathlon.engine.initialization;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import javax.xml.datatype.XMLGregorianCalendar;
import org.hackystat.devcathlon.configuration.ConfigurationManager;
import org.hackystat.devcathlon.configuration.jaxb.DevcathlonConfiguration;
import org.hackystat.devcathlon.engine.commentary.Comment;
import org.hackystat.devcathlon.engine.event.Event;
import org.hackystat.devcathlon.engine.event.EventScore;
import org.hackystat.devcathlon.engine.event.impl.BestCoverage;
import org.hackystat.devcathlon.engine.event.impl.BuildBeforeCommit;
import org.hackystat.devcathlon.engine.event.impl.DontWaitUntilLastMin;
import org.hackystat.devcathlon.engine.event.impl.EveryoneBuild;
import org.hackystat.devcathlon.engine.event.impl.FixTheBuild;
import org.hackystat.devcathlon.engine.event.impl.KeepTheCoverageHigh;
import org.hackystat.devcathlon.engine.event.impl.KeepTheRepositoryCleanDaily;
import org.hackystat.devcathlon.engine.event.impl.KeepTheRepositoryCleanHourly;
import org.hackystat.devcathlon.engine.event.impl.NoMias;
import org.hackystat.devcathlon.engine.match.Match;
import org.hackystat.devcathlon.engine.match.MatchManager;
import org.hackystat.devcathlon.engine.profile.ProfileManager;
import org.hackystat.devcathlon.engine.team.Team;
import org.hackystat.devcathlon.engine.team.TeamManager;
import org.hackystat.devcathlon.engine.user.User;
import org.hackystat.devcathlon.engine.user.UserManager;
import org.hackystat.sensorbase.client.SensorBaseClient;
import org.hackystat.sensorbase.resource.projects.jaxb.Project;
import org.hackystat.utilities.logger.HackystatLogger;
import org.hackystat.utilities.tstamp.Tstamp;

/**
 * Initialization class used to create test data.
 * 
 * @author John Zhou, John Ly
 */
public class Initialization {

  /**
   * Initialization.
   * 
   * @throws Exception If problems occur processing the initialization.
   */
  public Initialization() throws Exception {
    Logger logger = HackystatLogger.getLogger("org.hackystat.devcathlon", "devcathlon");
    ConfigurationManager manager = ConfigurationManager.getInstance();
    DevcathlonConfiguration config = manager.getConfiguration();

    // if only 1, it's likely to be the default
    // then don't initialize.
    if ((manager.getUsers() != null) && (manager.getUsers().size() > 1)) {
      String userEmail = "";
      String userPassword = "";
      String userFirstName = "";
      String userLastName = "";
      String userGender = "";
      String userContact = "";
      String userLocation = "";
      String userBioInfo = "";
      String userAvatar = "";
      
      String teamUtName = "TeamUT";
      String teamMsName = "TeamMS";

      String project = "hackystat-ui-devcathlon-jnancheta";
      String projectLeader = "jnancheta@gmail.com";
      String teamUtLeaderEmail = "anthony.m.du@gmail.com";
      String teamMsLeaderEmail = "robinraqueno@gmail.com";

      String[] teamUtEmails = { "john.cz.ly@gmail.com", "phillipkhlau@gmail.com",
          "scheller.sanchez@gmail.com", "anthony.m.du@gmail.com" };
      String[] teamMsEmails = { "john.km.zhou@gmail.com", "jnancheta@gmail.com",
          "dan.m.arakaki@gmail.com", "robinraqueno@gmail.com"};

      // [1] Create users in the configuration.xml file

      for (org.hackystat.devcathlon.configuration.jaxb.User user : config.getUsers().getUser()) {
        userFirstName = manager.getUserProperty(user, "FirstName");
        userLastName = manager.getUserProperty(user, "LastName");
        userEmail = manager.getUserProperty(user, "email");
        userPassword = manager.getUserProperty(user, "password");
        userGender = manager.getUserProperty(user, "gender");
        userLocation = manager.getUserProperty(user, "location");
        userContact = manager.getUserProperty(user, "contact");
        userBioInfo = manager.getUserProperty(user, "bioInfo");
        userAvatar = manager.getUserProperty(user, "avatar");
        
        User aUser = UserManager.getInstance().addUser(userFirstName, userLastName, 
                                                       userEmail, userPassword);
        ProfileManager.getInstance().addProfile(aUser, userGender, 
                                             userLocation, userContact, userBioInfo, userAvatar);
      }

      // [2] Create the teams.

      // [a] Establish the owners
      User teamUtOwner = UserManager.getInstance().getUser(teamUtLeaderEmail);
      User teamMsOwner = UserManager.getInstance().getUser(teamMsLeaderEmail);

      // [b] Establish the members
      Set<User> teamUtMembers = new HashSet<User>();
      for (String email : teamUtEmails) {
        if (UserManager.getInstance().getUser(email) != null) {
          teamUtMembers.add(UserManager.getInstance().getUser(email));
        }
      }

      Set<User> teamMsMembers = new HashSet<User>();
      for (String email : teamMsEmails) {
        if (UserManager.getInstance().getUser(email) != null) {
          teamMsMembers.add(UserManager.getInstance().getUser(email));
        }
      }

      // [c] Add teams to TeamManager
      Team teamUt = TeamManager.getInstance().addTeam(teamUtName, teamUtOwner, new HashSet<User>());
      TeamManager.getInstance().getTeam(teamUtName).setProjectName(project);
      TeamManager.getInstance().getTeam(teamUtName).setDescription(
          "Don't worry about it, it's over.");      
      TeamManager.getInstance().getTeam(teamUtName).setTeamLogoPath("Team4.png");
      TeamManager.getInstance().getTeam(teamUtName).sendInvites(teamUtMembers);
      
      Team teamMs = TeamManager.getInstance().addTeam(teamMsName, teamMsOwner, new HashSet<User>());
      TeamManager.getInstance().getTeam(teamMsName).setProjectName(project);
      TeamManager.getInstance().getTeam(teamMsName).setDescription("Ohayoo!!!");
      TeamManager.getInstance().getTeam(teamMsName).setTeamLogoPath("Team6.png");
      TeamManager.getInstance().getTeam(teamMsName).sendInvites(teamMsMembers);      
      
      TeamManager.getInstance().getTeam(teamUtName).acceptAllMemberInvites();
      TeamManager.getInstance().getTeam(teamMsName).acceptAllMemberInvites();
      
      // [3] Create the matches

      // [a] Retrieving actual sensorbase Java objects from hackystat

      String host = config.getHackystat().getSensorbase();
      String password = UserManager.getInstance().getUser(projectLeader).getPassword();

      SensorBaseClient client = new SensorBaseClient(host, projectLeader, password);
      Project devcathlonProject = client.getProject(projectLeader, project);
      
      TeamManager.getInstance().getTeam(teamMsName).setProject(devcathlonProject);
      TeamManager.getInstance().getTeam(teamUtName).setProject(devcathlonProject);

      // [b] Map the teams to the projects.

      Map<Team, Project> teams2projects = new HashMap<Team, Project>();
      teams2projects.put(teamUt, devcathlonProject);
      teams2projects.put(teamMs, devcathlonProject);

      // [c] Add the events to a list.

      List<Event> events1 = new ArrayList<Event>();
      events1.add(new BestCoverage());
      events1.add(new FixTheBuild());
      events1.add(new NoMias());

      List<Event> events2 = new ArrayList<Event>();
      events2.add(new BuildBeforeCommit());
      events2.add(new DontWaitUntilLastMin());
      events2.add(new EveryoneBuild());
      events2.add(new KeepTheCoverageHigh());

      List<Event> events3 = new ArrayList<Event>();
      events3.add(new KeepTheRepositoryCleanDaily());
      events3.add(new KeepTheRepositoryCleanHourly());
      //takes 5 mins to run
//      events3.add(new PassTheBuild());
//      events3.add(new CommitOften());
//      events3.add(new CollectiveOwnership());
      //triggers exception
//      events3.add(new RewardImprovedCoverage());
      
      List<Event> events4 = new ArrayList<Event>();
      events4.add(new EveryoneBuild());
      events4.add(new BuildBeforeCommit());
      
      List<Event> events5 = new ArrayList<Event>();
      events5.add(new BestCoverage());

      // [d] Create the team names.
      String matchName1 = "Battle of Devcathlon Virgins";
      String matchName2 = "Wicket Wicket Wicket";
      String matchName3 = "The Great Depression";
      String matchName4 = "Road to Redemption";
      String matchName5 = "Return of the Glory Days";

      // [f] Create the matches.
      XMLGregorianCalendar startDate = Tstamp.incrementDays(Tstamp.makeTimestamp(), -6);
      XMLGregorianCalendar endDate = Tstamp.incrementDays(startDate, 6);
      MatchManager.getInstance()
          .addMatch(matchName1, startDate, endDate, teams2projects, events1);
      MatchManager.getInstance().addMatch(matchName2, startDate, endDate, teams2projects, events2);
      MatchManager.getInstance().addMatch(matchName3, startDate, endDate, teams2projects, events3);
      startDate = Tstamp.incrementMilliseconds(endDate, 20);
      endDate = Tstamp.incrementDays(startDate, 7);
      MatchManager.getInstance().addMatch(matchName4, startDate, endDate, teams2projects, events4);
      startDate = Tstamp.incrementMilliseconds(endDate, 20);
      endDate = Tstamp.incrementDays(startDate, 7);
      MatchManager.getInstance().addMatch(matchName5, startDate, endDate, teams2projects, events5);
      
      for (Match match : MatchManager.getInstance().getAllMatches()) {
        for (Team team : match.getTeams()) {
          match.acceptMatchInvitation(team);
        }
      }

      // [f] Create the scores.
      Match match1 = MatchManager.getInstance().getMatch(matchName1);
      XMLGregorianCalendar scoredate1 = Tstamp.incrementMilliseconds(match1.getStartDate(), 10);
      Event event1 = events1.get(0);
      logger.info("Getting BestCoverage score");
      EventScore score1a = event1.computeScore(match1, teamMs, scoredate1);
      match1.addScore(score1a, event1);
      logger.info("Getting BestCoverage score");
      EventScore score1b = event1.computeScore(match1, teamUt, scoredate1);
      match1.addScore(score1b, event1);
      XMLGregorianCalendar scoredate2 = Tstamp.incrementMilliseconds(scoredate1, 10);
      Event event2 = events1.get(1);
      logger.info("Getting FixTheBuild score");
      EventScore score2a = event2.computeScore(match1, teamMs, scoredate2);
      match1.addScore(score2a, event2);
      logger.info("Getting FixTheBuild score");
      EventScore score2b = event2.computeScore(match1, teamUt, scoredate2);
      match1.addScore(score2b, event2);
      XMLGregorianCalendar scoredate3 = Tstamp.incrementMilliseconds(scoredate2, 10);    
      Event event3 = events1.get(2);
      logger.info("Getting NoMIAs score"); 
      //EventScore score3a = event3.computeScore(match1, teamMs, scoredate3);
      EventScore score3a = new EventScore(scoredate3, match1, teamMs,
      UserManager.getInstance().getUser("dan.m.arakaki@gmail.com"));
      score3a.setBaseScore(23);
      match1.addScore(event3, score3a);
      logger.info("Getting NoMIAs score");
      EventScore score3b = event3.computeScore(match1, teamUt, scoredate3);
      match1.addScore(score3b, event3);
      
      Match match2 = MatchManager.getInstance().getMatch(matchName2);
      XMLGregorianCalendar scoredate5 = Tstamp.incrementMilliseconds(match2.getStartDate(), 10);
      Event event5 = events2.get(0);
      logger.info("Getting BuildBeforeCommit score");
      EventScore score5a = event5.computeScore(match2, teamMs, scoredate5);
      match2.addScore(score5a, event5);
      logger.info("Getting BuildBeforeCommit score");
      EventScore score5b = event5.computeScore(match2, teamUt, scoredate5);
      match2.addScore(score5b, event5);
      XMLGregorianCalendar scoredate6 = Tstamp.incrementMilliseconds(scoredate5, 10);
      Event event6 = events2.get(1);
      logger.info("Getting DontWaitUntilLastMin score");
      EventScore score6a = event6.computeScore(match2, teamMs, scoredate6);
      match2.addScore(score6a, event6);
      logger.info("Getting DontWaitUntilLastMin score");
      EventScore score6b = event6.computeScore(match2, teamUt, scoredate6);
      match2.addScore(score6b, event6);
      XMLGregorianCalendar scoredate7 = Tstamp.incrementMilliseconds(scoredate6, 10);
      Event event7 = events2.get(2);
      logger.info("Getting EveryoneBuild score");
      EventScore score7a = event7.computeScore(match2, teamMs, scoredate7);
      match2.addScore(score7a, event7);
      logger.info("Getting EveryoneBuild score");
      //EventScore score7b = event7.computeScore(match2, teamUt, scoredate7);
      EventScore score7b = new EventScore(scoredate7, match2, teamUt,
      UserManager.getInstance().getUser("john.km.zhou@gmail.com"));
      score7b.setBaseScore(34);
      match2.addScore(event7, score7b);
      XMLGregorianCalendar scoredate8 = Tstamp.incrementMilliseconds(scoredate7, 10);
      Event event8 = events2.get(3);
      logger.info("Getting KeepTheCoverageHigh score");
      EventScore score8a = event8.computeScore(match2, teamMs, scoredate8);
      match2.addScore(score8a, event8);
      logger.info("Getting KeepTheCoverageHigh score");
      EventScore score8b = event8.computeScore(match2, teamUt, scoredate8);
      match2.addScore(score8b, event8);

      Match match3 = MatchManager.getInstance().getMatch(matchName3);
      XMLGregorianCalendar scoredate9 = Tstamp.incrementMilliseconds(match3.getStartDate(),
                                                             10);
      Event event9 = events3.get(0);
      logger.info("Getting KeepTheRepositoryCleanDaily score");
      EventScore score9a = event9.computeScore(match3, teamMs, scoredate9);
      match3.addScore(score9a, event9);
      logger.info("Getting KeepTheRepositoryCleanDaily score");
      //EventScore score9b = event9.computeScore(match3, teamUt, scoredate9);
      EventScore score9b = new EventScore(scoredate9, match3, teamUt,
      UserManager.getInstance().getUser("phillipkhlau@gmail.com"));
      score9b.setBaseScore(43);
      match3.addScore(event9, score9b);
      XMLGregorianCalendar scoredate10 = Tstamp.incrementMilliseconds(scoredate9, 10);
      Event event10 = events3.get(1);
      logger.info("Getting KeepTheRepositoryCleanHourly score");
      //EventScore score10a = event10.computeScore(match3, teamMs, scoredate10);
      EventScore score10a = new EventScore(scoredate10, match3, teamUt,
      UserManager.getInstance().getUser("john.cz.ly@gmail.com"));
      score10a.setBaseScore(54);
      match3.addScore(event10, score10a);
      logger.info("Getting KeepTheRepositoryCleanHourly score");
      //EventScore score10b = event10.computeScore(match3, teamUt, scoredate10);
      EventScore score10b = new EventScore(scoredate10, match3, teamUt,
      UserManager.getInstance().getUser("scheller.sanchez@gmail.com"));
      score10b.setBaseScore(78);
      match3.addScore(event10, score10b);

      // [f] Create the comments.
      Comment comment = new Comment(teamUtOwner, startDate, "Good Job");
      MatchManager.getInstance().getMatch(matchName1).addComment(comment);
    }
  }
}
